Unit BPeaUnit;

{$mode objfpc}{$H+}

Interface

Uses
  Classes, SysUtils, BListsUnit, BWebJSONUnit;

Type BPeaClass = Class;

Type BPropretyKind = (
  ppkUnknow = 0,
  ppkFirst = 1,
  ppkString = 1,
  ppkStrings = 2,
  ppkInteger = 3,
  ppkIntegers = 4,
  ppkDouble = 5,
  ppkDoubles = 6,
  ppkDate = 7,
  ppkDateTime = 8,
  ppkDateTimes = 9,
  ppkTime = 10,
  ppkPea = 11,
  ppkPeas = 12,
  ppkHolders = 13,
  ppkBoolean = 14,
  ppkBooleans = 15,
  ppkEnum = 16,
  ppkOther = 17,
  ppkLast = 17);

{$define ppkPlainPlural :=
  ppkStrings,
  ppkIntegers,
  ppkDoubles,
  ppkDateTimes,
  ppkBooleans
}

{$define ppkPlain :=
  ppkString,
  ppkInteger,
  ppkDouble,
  ppkDate,
  ppkDateTime,
  ppkTime,
  ppkBoolean,
  ppkEnum
}

Type

{ BEnumInfoValueClass }

 BEnumInfoValueClass = Class
  Private
    bCaption: String;
    bID: Integer;
    bName: String;
  Public
    Property ID: Integer Read bID;
    Property Name: String Read bName;
    Property Caption: String Read bCaption;

    Constructor Build(Const aID: Integer; Const aName, aCaption: String);
End;

Type BEnumValuesList = Specialize BPrimitiveList<BEnumInfoValueClass>;

Type

{ BEnumInfoClass }

 BEnumInfoClass = Class
  Private
    bPrefix: String;
    bValues: BEnumValuesList;
  Public
    Property Prefix: String Read bPrefix;
    Property Values: BEnumValuesList Read bValues;

    Procedure AddEnumInfo(Const aID: Integer; Const aName, aCaption: String);
    Constructor Build(Const aInfo: String);
End;


Type

{ BPeaPropertyClass }

 BPeaPropertyClass = Class
  Private
    bCaption: String;
    bEnum: BEnumInfoClass;
    bPluralCaption: String;
    bSQLCaption: String;
    bID: Integer;
    bKind: BPropretyKind;
    bPea: BPeaClass;
    Function GetIsPlural: Boolean;
    Function GetKindCtrl: String;
    Function GetKindQuery: String;
    Function GetKindSQL: String;
    Function GetKindString: String;
    Function GetKindUnlocked: String;
    Function GetSQLCaption: String;
    Procedure Initialize(Const aCaption, aPluralCaption, aSQLCaption: String;
      Const aKind: BPropretyKind);
  Public
    Property Caption: String Read bCaption Write bCaption;
    Property PluralCaption: String Read bPluralCaption Write bPluralCaption;
    Property SQLCaption: String Read GetSQLCaption Write bSQLCaption;

    Property Kind: BPropretyKind Read bKind Write bKind;
    Property KindString: String Read GetKindString;
    Property KindSQL: String Read GetKindSQL;
    Property KindQuery: String Read GetKindQuery;
    Property KindUnlocked: String Read GetKindUnlocked;
    Property KindCtrl: String Read GetKindCtrl;

    Property Pea: BPeaClass Read bPea Write bPea;
    Property EnumInfo: BEnumInfoClass Read bEnum Write bEnum;

    Property IsPlural: Boolean Read GetIsPlural;

    Constructor Build(Const aCaption, aPluralCaption, aSQLCaption: String;
      Const aKindString: String; Const aEnumInfo: String);
    Destructor Burn;
End;

Type BPropertiesList = Specialize BPrimitiveList<BPeaPropertyClass>;

Type BPeaKind = (
  pkUnknow = 0,
  pkStart = 1,
  pkPlain = 1,
  pkTree = 2,
  pkHolder = 3,
  pkLast = 3);

Type

{ BPeaClass }

BPeaClass = Class
  Private
    bHoldingPea: BPeaClass;
    bID: Integer;
    bCaption: String;
    bKind: BPeaKind;
    bPluralCaption: String;
    bProperties: BPropertiesList;
    Function GetProperties(aIndex: Integer): BPeaPropertyClass;
  Public
    Property ID: Integer Read bID Write bID;
    Property Kind: BPeaKind Read bKind Write bKind;
    Property Caption: String Read bCaption Write bCaption;
    Property PluralCaption: String Read bPluralCaption Write bPluralCaption;
    Property HoldingPea: BPeaClass Read bHoldingPea Write bHoldingPea;
    Property &Property[aIndex: Integer]: BPeaPropertyClass
      Read GetProperties; Default;

    Property Properties: BPropertiesList Read bProperties;

    Procedure AddProperty(Const aProperty: BPeaPropertyClass);
    Function HasHolder(Const aPea: BPeaClass): Boolean;
    Function GetHolder(Const aPea: BPeaClass): BPeaPropertyClass;

    Constructor Build(Const aID: Integer;
      Const aKind, aCaption, aPluralCaption: String;
      Const aHoldingPea: BPeaClass);

    Destructor Burn;
End;

Type BPeasList = Specialize BPrimitiveList<BPeaClass>;

Implementation

Var
  NullPea: BPeaClass;

{ BEnumInfoClass }

Procedure BEnumInfoClass.AddEnumInfo(Const aID: Integer; Const aName,
  aCaption: String);
Begin
  bValues.Add(BEnumInfoValueClass.Build(aID, aName, aCaption));
End;

Constructor BEnumInfoClass.Build(Const aInfo: String);
Var
  i, aID: Integer;
  aBuffer: BStringsList;
  aValuesString, aCaption, aName: String;
Begin
  bValues := BEnumValuesList.Build;
  bPrefix := GetJSStr(aInfo, 'prefix');
  aValuesString := GetJSArr(aInfo, 'values');
  aBuffer := BStringsList.Build;
  GetJSObjList(aValuesString, aBuffer);
  For i := 0 To aBuffer.Count - 1 Do
    Begin
      aID := GetJSInt(aBuffer[i], 'id');
      aName := GetJSStr(aBuffer[i], 'name');
      aCaption := GetJSStr(aBuffer[i], 'caption');
      bValues.Add(BEnumInfoValueClass.Build(aID, aName, aCaption));
    End;
End;

{ BEnumInfoValueClass }

Constructor BEnumInfoValueClass.Build(Const aID: Integer; Const aName,
  aCaption: String);
Begin
  bID := aID;
  bName := aName;
  bCaption := aCaption;
End;

{ BPeaPropertyClass }

Function BPeaPropertyClass.GetKindString: String;
Begin
  Result := '';
  Case bKind Of
    ppkString: Result := 'String';
    ppkStrings: Result := 'BStringsThreadList';
    ppkInteger: Result := 'Integer';
    ppkIntegers: Result := 'BIntegersThreadList';
    ppkDouble: Result := 'Double';
    ppkDoubles: Result := 'BDoublesThreadList';
    ppkDate: Result := 'TDate';
    ppkDateTime: Result := 'TDateTime';
    ppkDateTimes: Result := 'BDateTimesThreadList';
    ppkTime: Result := 'TTime';
    ppkBoolean: Result := 'Boolean';
    ppkBooleans: Result := 'BBooleansThreadList';
    ppkPea: Result := Format('B%sClass', [bPea.Caption]);
    ppkPeas: Result := Format('B%sThreadList', [bPea.PluralCaption]);
    ppkHolders: Result := Format('B%sThreadList', [bPea.PluralCaption]);
    ppkEnum: Result := 'Integer';
  End;
end;

Function BPeaPropertyClass.GetKindUnlocked: String;
Begin
  Result := '';
  Case bKind Of
    ppkString: Result := 'String';
    ppkStrings: Result := 'BStringsList';
    ppkInteger: Result := 'Integer';
    ppkIntegers: Result := 'BIntegersList';
    ppkDouble: Result := 'Double';
    ppkDoubles: Result := 'BDoublesList';
    ppkDate: Result := 'TDate';
    ppkDateTime: Result := 'TDateTime';
    ppkDateTimes: Result := 'BDateTimesList';
    ppkTime: Result := 'TTime';
    ppkBoolean: Result := 'Boolean';
    ppkBooleans: Result := 'BBooleansList';
    ppkPea: Result := Format('B%sClass', [bPea.Caption]);
    ppkPeas: Result := Format('B%sList', [bPea.PluralCaption]);
    ppkHolders: Result := Format('B%sList', [bPea.PluralCaption]);
    ppkEnum: Result := 'Integer';
  End;
end;

Function BPeaPropertyClass.GetSQLCaption: String;
Begin
  Result := bSQLCaption;
  If IsPlural Then
    If Kind = ppkPeas Then
      Result := Copy(Result, 1, 28 - Length(Pea.Caption))
    Else
      Result := Copy(Result, 1, 28 - Length(Caption))
end;

Function BPeaPropertyClass.GetKindSQL: String;
Begin
  Case bKind Of
    ppkString: Result := 'VARCHAR(1024)';
    ppkStrings: Result := 'VARCHAR(1024)';
    ppkInteger: Result := 'INTEGER';
    ppkIntegers: Result := 'INTEGER';
    ppkDouble: Result := 'DOUBLE PRECISION';
    ppkDoubles: Result := 'DOUBLE PRECISION';
    ppkDate: Result := 'DATE';
    ppkDateTime: Result := 'TIMESTAMP';
    ppkDateTimes: Result := 'TIMESTAMP';
    ppkTime: Result := 'TIME';
    ppkBoolean: Result := 'INTEGER';
    ppkBooleans: Result := 'INTEGER';
    ppkPea: Result := 'INTEGER';
    ppkPeas: Result := 'INTEGER';
    ppkHolders: Result := 'INTEGER';
    ppkEnum: Result := 'INTEGER';
  End;
end;

Function BPeaPropertyClass.GetIsPlural: Boolean;
Begin
  Result := bKind In [ppkStrings, ppkIntegers, ppkDoubles, ppkDateTimes,
    ppkBooleans, ppkPeas, ppkHolders];
end;

Function BPeaPropertyClass.GetKindCtrl: String;
Begin
  Result := '';
  Case bKind Of
    ppkString: Result := 'String';
    ppkStrings: Result := 'String';
    ppkInteger: Result := 'Integer';
    ppkIntegers: Result := 'String';
    ppkDouble: Result := 'Double';
    ppkDoubles: Result := 'String';
    ppkDate: Result := 'TDate';
    ppkDateTime: Result := 'TDateTime';
    ppkDateTimes: Result := 'String';
    ppkTime: Result := 'TTime';
    ppkBoolean: Result := 'Boolean';
    ppkBooleans: Result := 'String';
    ppkPea: Result := 'Integer';
    ppkPeas: Result := 'String';
    ppkHolders: Result := 'String';
    ppkEnum: Result := 'Integer';
  End;
end;

Function BPeaPropertyClass.GetKindQuery: String;
Begin
  Case bKind Of
    ppkString: Result := 'ByString';
    ppkStrings: Result := 'ByString';
    ppkInteger: Result := 'ByInteger';
    ppkIntegers: Result := 'ByInteger';
    ppkDouble: Result := 'ByDouble';
    ppkDoubles: Result := 'ByDouble';
    ppkDate: Result := 'ByDateTime';
    ppkDateTime: Result := 'ByDateTime';
    ppkDateTimes: Result := 'ByDateTime';
    ppkTime: Result := 'ByDateTime';
    ppkBoolean: Result := 'ByBoolean';
    ppkBooleans: Result := 'ByBoolean';
    ppkPea: Result := 'ByInteger';
    ppkPeas: Result := 'ByInteger';
    ppkHolders: Result := 'ByInteger';
    ppkEnum: Result := 'ByInteger';
  End;
end;

Procedure BPeaPropertyClass.Initialize(Const aCaption, aPluralCaption,
  aSQLCaption: String; Const aKind: BPropretyKind);
Begin
  bKind := aKind;
  bCaption := aCaption;
  bPluralCaption := aPluralCaption;
  bSQLCaption := aSQLCaption;
End;

Constructor BPeaPropertyClass.Build(Const aCaption, aPluralCaption,
  aSQLCaption: String; Const aKindString: String; Const aEnumInfo: String);
Var
  aKind: BPropretyKind;
Begin
  Case aKindString Of
    'string': aKind := ppkString;
    'strings': aKind := ppkStrings;
    'integer': aKind := ppkInteger;
    'integers': aKind := ppkIntegers;
    'double': aKind := ppkDouble;
    'doubles': aKind := ppkDoubles;
    'date': aKind := ppkDate;
    'dateTime': aKind := ppkDateTime;
    'dateTimes': aKind := ppkDateTimes;
    'time': aKind := ppkTime;
    'boolean': aKind := ppkBoolean;
    'booleans': aKind := ppkBooleans;
    'pea': aKind := ppkPea;
    'peas': aKind := ppkPeas;
    'holders': aKind := ppkHolders;
    'enum': aKind := ppkEnum;
  End;
  bEnum := BEnumInfoClass.Build(aEnumInfo);
  Initialize(aCaption, aPluralCaption, aSQLCaption, aKind);
  Pea := NullPea;

End;

Destructor BPeaPropertyClass.Burn;
Begin

End;

{ BPeaClass }

Function BPeaClass.GetProperties(aIndex: Integer): BPeaPropertyClass;
Begin
  Result := bProperties[aIndex];
end;

Procedure BPeaClass.AddProperty(Const aProperty: BPeaPropertyClass);
Begin
  bProperties.Add(aProperty);
End;

Function BPeaClass.HasHolder(Const aPea: BPeaClass): Boolean;
Var
  i: Integer;
Begin
  Result := FALSE;
  If Not(aPea.Kind = pkHolder) Then Exit;
  For i := 0 To Properties.Count - 1 Do
    If (Properties[i].Kind = ppkHolders) And (Properties[i].Pea = aPea) Then
      Exit(TRUE);
End;

Function BPeaClass.GetHolder(Const aPea: BPeaClass): BPeaPropertyClass;
Var
  i: Integer;
Begin
  Result := nil;
  If Not(aPea.Kind = pkHolder) Then Exit;
  For i := 0 To Properties.Count - 1 Do
    If (Properties[i].Kind = ppkHolders) And (Properties[i].Pea = aPea) Then
      Exit(Properties[i]);
End;

Constructor BPeaClass.Build(Const aID: Integer; Const aKind, aCaption,
  aPluralCaption: String; Const aHoldingPea: BPeaClass);
Begin
  bID := aID;
  bCaption := aCaption;
  bPluralCaption := aPluralCaption;
  Case aKind Of
    'plain': bKind := pkPlain;
    'tree': bKind := pkTree;
    'holder': bKind := pkHolder;
  End;
  If aHoldingPea = nil Then
    bHoldingPea := NullPea
  Else
    bHoldingPea := aHoldingPea;
  bProperties := BPropertiesList.Create;
End;

Destructor BPeaClass.Burn;
Begin
  bProperties.Free;
End;

Initialization
Begin
  NullPea := BPeaClass.Build(-1, '', '', '', NullPea)
End;

Finalization
Begin
  NullPea.Burn;
End;

End.

